package main;
// 最新版本：3线程同时处理邮件正文、附件
// 以后可以改的地方就是把3线程改成线程池
// 我说为什么这个代码跑得没有foxmail快，估计就是这个原因了

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.mail.Flags.Flag;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.search.SearchTerm;
import javax.mail.search.SentDateTerm;

import tools.TimeProcesser;

import com.sun.mail.imap.IMAPFolder;

class customMsg {
	public int total;
	public int seq;
	public int number;
	public customMsg(){}
	public customMsg(int total, int seq, int number) {
		this.total = total;
		this.seq = seq;
		this.number = number;
	}
};

class Savemail implements Runnable {
	public Message msg = null;
	public StringBuffer filename = null;
	public StringBuffer head = null;
	public StringBuffer body = null;
	public StringBuffer attachment = null;
	public String path = null;
	public customMsg cm = null;
	
	public static final ConcurrentHashMap<Long, Message> allMail = new ConcurrentHashMap<Long, Message>(); 

	final String[] versions = { "", "1.0", "1.1", "1.2", "1.3", "1.4",
	"1.5" };
	
	public Savemail() {}
	
	public boolean fileExist(String path, String filename) {
		File textFile, attachFile;
		for (String ver : versions) {
			attachFile = new File(path + "/" + ver + "/" + filename
					+ ".attach.txt");
			textFile = new File(path + "/" + ver + "/" + filename + ".text.txt");
			if (attachFile.exists() || textFile.exists()) {
				return true;
			}
		}
		return false;
	}
	
	public boolean init() throws Exception{
		head = new StringBuffer();
		filename = new StringBuffer();
		body = new StringBuffer();
		attachment = new StringBuffer();

//		Date d = msg.getReceivedDate();
//		filename.append("" + (d.getMonth() + 1) + "-" + d.getDate()
//				+ "-");
//		filename.append(cm.number);
//
//		if (fileExist(path, filename.toString())) {
//			System.out.println("warning[ "+cm.seq + " already exist! ]");
//			return false;
//		}

		head.append("Subject: " + msg.getSubject());
		head.append("\nFrom: " + msg.getFrom()[0]);
//		head.append("\nTo: " + msg.getAllRecipients()[0]);
		head.append("\nDate: " + msg.getReceivedDate());
		return true;
	}
	
	public Savemail(Message msg, customMsg cm, String path) {
		this.msg = msg;
		this.path = path;
		this.cm = cm;
	}

	public String ripHtml(String html) {
		StringBuffer sb = new StringBuffer();
		String tag = "";
		int a = 0, s = 1, t = 1;
		while (s >= 0) {
			s = html.indexOf("<", a);
			t = html.indexOf(">", s);
			if (s < 0 || t < 0) {
				if (a < html.length())
					sb.append(html.substring(a, html.length()));
				break;
			}
			tag = html.substring(s + 1, t);
			sb.append(html.substring(a, s));
			if (tag.indexOf("br") != -1) {
				sb.append("\n");
			}
			a = t + 1;
		}
		return sb.toString();
	}

	public boolean isAttachment(Part part) {
		try {
			String contenttype = part.getContentType();
			String disposition = part.getDisposition();
			String filename = part.getFileName();

			contenttype = contenttype == null ? "" : contenttype.toLowerCase();
			disposition = disposition == null ? "" : disposition.toLowerCase();
			filename = filename == null ? "" : filename.toLowerCase();

			if (contenttype.indexOf("name") != -1
					|| ((disposition.indexOf("attachment") != -1) && (filename
							.length() > 0)))
				return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	public void getMailContent(Part part, StringBuffer bodytext,
			StringBuffer attachment) throws Exception {
		boolean conname = isAttachment(part);

		if ((part.isMimeType("text/plain")) && !conname) {
			if (bodytext.length() > 0)
				bodytext.delete(0, bodytext.length());
			bodytext.append((String) part.getContent());
		} else if (part.isMimeType("text/html") && !conname) {
			if (bodytext.length() == 0)
				bodytext.append(ripHtml((String) part.getContent()));
		} else if (part.isMimeType("multipart/*")) {
			Multipart multipart = (Multipart) part.getContent();
			int counts = multipart.getCount();
			for (int i = 0; i < counts; i++) {
				getMailContent(multipart.getBodyPart(i), bodytext, attachment);
			}
		} else if (part.isMimeType("message/rfc822")) {
			getMailContent((Part) part.getContent(), bodytext, attachment);
		} else if (conname && part.isMimeType("text/plain")) {
			String contentType = part.getContentType();
			String charset = "";
			Pattern p = Pattern.compile("charset=([0-9a-zA-Z]*);");
			Matcher m = p.matcher(contentType);
			if (m.find()) {
				charset = m.group(1);
			}

			if (charset.equalsIgnoreCase("cp932")) {
				InputStream is = part.getInputStream();
				// filename
				char[] temp = new char[1000];
				BufferedReader reader = new BufferedReader(
						new InputStreamReader(is));

				int status = reader.read(temp);
				while (status != -1) {
					attachment.append(temp);
					status = reader.read(temp);
				}

			} else
				attachment.append((String) part.getContent());
		}
	}

	public String getVersionName(String body) {
		Pattern p = Pattern.compile("VersionName=([0-9\\.]*)");
		Matcher m = p.matcher(body);
		if (m.find()) {
			return m.group(1);
		}
		return new String("");
	}

	public void writeToFile(StringBuffer filename, StringBuffer body,
			StringBuffer attach, String path) throws Exception {
		String versionName = getVersionName(body.toString());

		PrintWriter pw1 = null;
		PrintWriter pw2 = null;
		try {
			File file = new File(path + "/" + versionName);
			file.mkdirs();

			pw1 = new PrintWriter(new FileWriter(path + "/" + versionName + "/"
					+ filename.toString() + ".attach.txt"));
			pw2 = new PrintWriter(new FileWriter(path + "/" + versionName + "/"
					+ filename.toString() + ".text.txt"));

			pw1.println(attach.toString());
			pw2.println(body.toString());
		} catch (IOException e) {
			throw e;
		} finally {
			if (pw1 != null)
				pw1.close();
			if (pw2 != null)
				pw2.close();
		}
	}

	public void run() {
		try {
			System.out.println("# MESSAGE " + cm.seq + "/" + cm.total + " , " + cm.number);
			
			if(!init())
				return;
			
			getMailContent(msg, body, attachment);
			allMail.put(msg.getReceivedDate().getTime(), msg);
			System.out.println(TimeProcesser.getDateByUnixTime(msg.getReceivedDate().getTime()) + "	" + msg.getContent());
//		    writeToFile(filename, head.append(body), attachment, path);
		} catch (Exception e) {
			System.out.println(head);
			System.out.println(filename);			
			e.printStackTrace();			
		}
	}
}

public class FolderFetchIMAP {
	IMAPFolder folder = null;
	Store store = null;
	Flag flag = null;

	public static Thread th1 = null;
	public static Thread th2 = null;
	public static Thread th3 = null;
	
	public void init(String username, String password) {
		// init...
		try {
			Properties props = System.getProperties();
			props.setProperty("mail.store.protocol", "imaps");
			Session session = Session.getDefaultInstance(props, null);
			store = session.getStore("imaps");
			store.connect("imap.googlemail.com", username, password);
			folder = (IMAPFolder) store.getFolder("Notes");
			if (!folder.isOpen())
				folder.open(Folder.READ_ONLY);
		} catch (Exception e) {
			e.printStackTrace();
			return;
		}
	}

	public Message[] getMsgAfterDate(String date) {
		try {
			SearchTerm st = new SentDateTerm(SentDateTerm.GT,
					getSearchDate(date));
			return folder.search(st);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}



	private void fetchMail(String username, String password, String date,
			String path) throws MessagingException, IOException {
		try {
			init(username, password);
			Message[] messages = getMsgAfterDate(date);

			System.out.println("Num of Messages : " + messages.length);

			for (int i = 0; i < messages.length; i++) {
//				if(i<2198) continue;
				Message msg = messages[i];
				customMsg cm = new customMsg(messages.length, i+1, msg.getMessageNumber());
				try {
					Savemail h1 = new Savemail(msg, cm, path);
					while (true) {
						if (th1 == null || !th1.isAlive()) {
							th1 = new Thread(h1);
							th1.start();
							break;
						}
						if (th2 == null || !th2.isAlive()) {
							th2 = new Thread(h1);
							th2.start();
							break;
						}
						if (th3 == null || !th3.isAlive()) {
							th3 = new Thread(h1);
							th3.start();
							break;
						}						
					}
				} catch (Exception e) {
					e.printStackTrace();
					continue;
				}


			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			boolean ending = true;
			while(th1.isAlive() || th2.isAlive())
			{
				if(ending) {
					System.out.println("Will exit soon...");
					ending = false;
				}
			}
			if (folder != null && folder.isOpen()) {
				folder.close(true);
			}
			if (store != null) {
				store.close();
			}
		}
	}

	private Date getSearchDate(String date) {
		String[] ymd = date.split("-");
		int year, month, day;
		Date srchdate = null;
		try {
			year = Integer.parseInt(ymd[0]);
			month = Integer.parseInt(ymd[1]) - 1;
			day = Integer.parseInt(ymd[2]);
			Calendar cal = Calendar.getInstance();
			cal.set(year, month, day);
			srchdate = cal.getTime();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return srchdate;
	}

	public static void main(String[] args) throws MessagingException,
			IOException {
		FolderFetchIMAP mail = new FolderFetchIMAP();
//		if (args.length >= 3) {
//			String path = "";
//			if (args.length == 4)
//				path = args[3];
//		}
		mail.fetchMail("everestlion@gmail.com", "283848808", "2010-12-15", "Notes");
		
		System.out.println("=======" + Savemail.allMail.size());
	}
}